package com.spring.demo.untils.document.handle;

import com.alibaba.fastjson.JSON;
import com.spring.demo.untils.document.ClassUtils;
import com.spring.demo.untils.document.OrderMapping;
import com.spring.demo.untils.document.annotions.Mapper;
import com.spring.demo.untils.document.annotions.Mapping;
import com.spring.demo.untils.document.config.GlobalConfig;
import lombok.Data;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.*;

/**
 * @author xuweizhi
 * @since 2023/04/26 10:34
 */
@Data
public class MapMapping<T> implements OutputHandle<T> {

    private GlobalConfig globalConfig;

    private List<OrderMapping> orderMappingList;

    private Boolean isJsonStr = false;

    public MapMapping(GlobalConfig globalConfig, List<OrderMapping> orderMappingList) {
        this.globalConfig = globalConfig;
        this.orderMappingList = orderMappingList;
    }

    private Class<T> clazz;


    @SuppressWarnings("all")
    public T handle(String line) {
        Object instance;
        try {
            if (this.isJsonStr) {
                return JSON.parseObject(line, clazz);
            }

            String[] split = line.split(globalConfig.getSplit());
            Constructor<?> declaredConstructor = clazz.getDeclaredConstructor();
            declaredConstructor.setAccessible(true);
            instance = declaredConstructor.newInstance();

            List<Class> classes = Arrays.asList(clazz.getInterfaces());

            if (classes.contains(Map.class)) {
                OrderMapping orderMapping = orderMappingList.get(0);
                T t = clazz.newInstance();
                instance = new HashMap<Object,Object>();
                ((HashMap<Object, Object>) instance).put(split[orderMapping.getKeyIndex()], split[orderMapping.getValueIndex()]);
                return (T) instance;
            } else if (classes.contains(List.class)) {
                instance = new ArrayList();
                OrderMapping orderMapping = orderMappingList.get(0);
                ((ArrayList<Object>) instance).add(split[orderMapping.getValueIndex()]);
            } else if (ClassUtils.isPrimitiveOrWrapper(clazz) || Objects.equals(String.class, clazz)) {
                OrderMapping orderMapping = orderMappingList.get(0);
                instance = split[orderMapping.getValueIndex()];
            } else {
                if (orderMappingList != null) {
                    // 按照字段映射赋值
                    for (OrderMapping orderMapping : orderMappingList) {
                        Field declaredField = clazz.getDeclaredField(orderMapping.getFiledName());
                        declaredField.setAccessible(true);
                        declaredField.set(instance, split[orderMapping.getValueIndex()]);
                    }
                } else if (clazz.isAnnotationPresent(Mapper.class)) {
                    Field[] declaredFields = clazz.getDeclaredFields();
                    // 按照注解赋值
                    for (Field declaredField : declaredFields) {
                        if (declaredField.isAnnotationPresent(Mapping.class)) {
                            declaredField.setAccessible(true);
                            Mapping mapping = declaredField.getAnnotation(Mapping.class);
                            if (mapping != null) {
                                declaredField.set(instance, split[mapping.index()]);
                            }
                        }
                    }
                } else {
                    for (String value : split) {
                        // 按照分割符赋值
                        if (value.contains(":")) {
                            String[] filedValue = value.split(":");
                            Field declaredField = clazz.getDeclaredField(filedValue[0]);
                            if (declaredField != null) {
                                declaredField.setAccessible(true);
                                declaredField.set(instance, filedValue[1]);

                            }
                        }
                    }
                }

            }
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        } catch (NoSuchFieldException e) {
            throw new RuntimeException(e);
        }

        return (T) instance;

    }
}

